/*
* ========== Copyright Header Begin ==========================================
* 
* OpenSPARC T1 Processor File: lexer.l
* Copyright (c) 2006 Sun Microsystems, Inc.  All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
* 
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
* 
* The above named program is distributed in the hope that it will be 
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* General Public License for more details.
* 
* You should have received a copy of the GNU General Public
* License along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
* 
* ========== Copyright Header End ============================================
*/
%{
	/* any C includes here */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>

#include "basics.h"
#include "allocate.h"
#include "lexer.h"
#include "simcore.h"
#include "config.h"
#include "fatal.h"

lexer_t lex;	/* additional return value info */

#if TESTRIG /* { */
#include <stdarg.h>
#include <errno.h>
void fatal(char *s,...);
#endif		/* } */

%}

DECNUM	("0"|([1-9][0-9]*))

%x comment
%x string

%%

<<EOF>>			return T_EOF;

"{"			return T_L_Brace;

"}"			return T_R_Brace;

";"			return T_S_Colon;

"+"			return T_Plus;

"-"			return T_Minus;

","			return T_Comma;

^"#"[ \t].*$		{
				char lbuf[1024];
				int num;
				if (sscanf(lextext,"# %d \"%[^\"]\"", &num, lbuf)!=2)
					lex_fatal("Illegal # directive");
				lex.linenum = num-1;
				if (lex.fnamep != (char*)0) Xfree(lex.fnamep);
				lex.fnamep = Xstrdup(lbuf);
			}

\"			BEGIN(string);
<string>\"		BEGIN(INITIAL);

<string>([^"\n]|(\\\"))*	{
				lex.strp = lextext;
                                return T_String;
			}

<string>\n		{
				lex_fatal("unterminated string");
			}


"0x"[0-9A-F][0-9A-F]*	{
				lex.val = strtoll(lextext, (char **)NULL, 16);
				return T_Number;
			}

"0x"[0-9a-f][0-9a-f]*	{
				lex.val = strtoll(lextext, (char **)NULL, 16);
				return T_Number;
			}

{DECNUM}[KkMmGg]	{
				char * ep;
				lex.val = strtoll(lextext, &ep, 10);
				switch(*ep) {
				case 'G': case 'g':
					lex.val <<= 30;
					break;
				case 'M': case 'm':
					lex.val <<= 20;
					break;
				case 'K': case 'k':
					lex.val <<= 10;
					break;
				default:
					lex_fatal("parsing number");
				}
				return T_Number;
			}

{DECNUM}		{
				lex.val = atoll(lextext);
				return T_Number;
			}


[A-Za-z_][A-Za-z_0-9]*	{
				lex.strp = lextext;
				return T_Token;
			}

			/* Note: . = any character EXCEPT newline */
\/\/.*			{ /* nada - swallow single line comments */ }

[\t ]*			{ /* nada - swallow white space */ }


"\n"			{
				lex.linenum ++;
			}

.			{
				lex_fatal("Illegal character %s", lextext);
			}

%%







void init_lexer(char * fnamep, FILE *fp, char * cleanup_filep)
{
	lex.cleanup_filep = cleanup_filep ? Xstrdup(cleanup_filep) : (char*)0;
	lex.linenum = 1;
	lex.fnamep = Xstrdup(fnamep);

	lex.ungot_available = false;
	lex.last_token = T_Error;

	lexin = fp;
}


lexer_tok_t lex_get_token()
{
	if (lex.ungot_available) {
		lex.ungot_available = false;
		return lex.last_token;
	}

	lex.last_token = lexlex();

	return lex.last_token;
}



void lex_unget()
{
	if (lex.ungot_available) fatal("Internal error, lex_unget with token already ungot");

	lex.ungot_available = true;
}


void lex_get(lexer_tok_t expected)
{
	lexer_tok_t tok;
	char *s;
	char buffer[1024];

	tok = lex_get_token();

	if (tok == expected) return;

	switch(tok) {
	case	T_EOF:		s="end of file";	break;
	case	T_L_Brace:	s="{";	break;
	case	T_R_Brace:	s="}";	break;
	case	T_S_Colon:	s=";";	break;
	case	T_Plus:		s="+";	break;
	case	T_Minus:	s="-";	break;
	case	T_Number:	s="number";	break;
	case	T_String:	s="string";	break;
	case	T_Token:
		sprintf(buffer,"token %s", lex.strp);
		s=buffer;
		break;
	case	T_Error:	s="error";	break;
	default:
		s="unknown token - internal error";
		break;
	}

	lex_fatal("unexpected %s", s);
}


	/*
	 * Special version of fatal for the lexer
	 * to enable cleanup of stuff before death
	 */

void lex_fatal(char * fmt, ...)
{
	va_list	args;

	if (errno!=0) perror("FATAL: "); else fprintf(stderr,"FATAL: ");
	if (fmt) {
		va_start(args, fmt);
		(void)vfprintf(stderr, fmt, args);

		va_end(args);
	}

	if (lex.cleanup_filep != (char *)0) {
		unlink(lex.cleanup_filep);
		Xfree(lex.cleanup_filep);
	}
	fprintf(stderr," at line %d of %s\n", lex.linenum, lex.fnamep);
	Xfree(lex.fnamep);

SANITY(	lex.fnamep = (char*)0; );
SANITY(	lex.cleanup_filep = (char*)0; );
	exit(1);
}



int lexwrap()
{
	return 1;
}

#if TESTRIG /* { */
main()
{
	lexer_tok_t tok;

	lex.linenum = 1;
	lex.fnamep = "test";

	do {
		tok = lexlex();

		fprintf(stderr,"token = %d at line %d in %s\n",tok, lex.linenum, lex.fnamep);
	} while (tok!=T_Error && tok!=T_EOF);
}


void fatal(char* fmt, ...)
{
	va_list 	args;
	int		status;
	
	if (errno!=0) perror("FATAL: "); else fprintf(stderr,"FATAL: ");
	if (fmt) {
		va_start(args, fmt);
		(void)vfprintf(stderr, fmt, args);

		va_end(args);
	}

	fprintf(stderr,"\n");
	fflush(stderr);
	fflush(stdout);

	thr_exit(&status);
}

#endif /* } */
